package montecarlothreads.multithread;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.swing.JOptionPane;
import montecarlothreads.MonteCarloThreads;
//Multi thread algorithm for monte carlo
public class multi extends Thread {
	public int cores;
        public int poolSize;
        public double blockingCoef;
        public int j;
        public static int progressBar1,progressBar2;
        public static int nbSim = 1;
        public boolean running;
        
	public multi(  final String CallPutFlag,
                        final double s,
                        final double x,
                        final double r, 
                        final double t,
                        final double b,
                        final double v,
			final int nbSteps,
                        final int nbSimulation
                        ) throws InterruptedException, ExecutionException{
            nbSim = nbSimulation;
            running = true;
        Runnable runner1 = new Runnable()
                    {
                        
                    public void run() {
                        while (running){
                    MonteCarloThreads.mainFrame.jProgressBar1.setValue((9*progressBar1/(10*(nbSim/100)) + progressBar2/(10*(nbSim/100))));
                        }
};};
    Thread thread1 = new Thread(runner1, "loop");
    thread1.start();
            
            
            
                //Start timing
                long start = System.currentTimeMillis();
                
                //Declarations, initializations
                cores = Runtime.getRuntime().availableProcessors();
                blockingCoef = 0.1;
                poolSize = (int) (cores/(1-blockingCoef));
                final double st;
                double sum = 0;
                
                final double dt = t/nbSteps;
		final double drift = dt*(b-java.lang.Math.pow(v,2)/2);
		final double vSqrdt = v*java.lang.Math.sqrt(dt);
                final ExecutorService execPool = Executors.newFixedThreadPool(poolSize);
                
                int z = 0;
		if(CallPutFlag.equals("c")){
		z = 1;
		}
                else if (CallPutFlag.equals("p")){
		z = -1;
		}
                st = 0;
                
                final List<Callable<Double>> partition = new ArrayList<Callable<Double>>();
                for(j=0 ; j<nbSimulation ; j++){
                    //MonteCarloThreads.mainFrame.jProgressBar1.setValue((j/((nbSimulation-1)/100))/3);
                    partition.add(new Callable<Double>() 
		    {
                        @Override
		    	public Double call() throws Exception
		    	{
		    			 return thread(   CallPutFlag,
                                                            s,
                                                            x,
                                                            t,
                                                            r,
                                                            b,
                                                            v,
                                                            nbSteps,
                                                            nbSimulation,
                                                            s,
                                                            dt,
                                                            drift,
                                                            vSqrdt);
                        }
		    }
                );
                }
		List<Future<Double>> values = execPool.invokeAll(partition);
                int count = 0;
		for(Future<Double> value : values){
                        count++;
                        sum = sum + Math.max((value.get()-x)*z,0);
                        //MonteCarloThreads.mainFrame.jProgressBar1.setValue(50);

                        //MonteCarloThreads.mainFrame.jProgressBar1.setValue((nbSimulation/3000)+ (2 * count)/((nbSimulation-1) * 3000));

                         progressBar2++;
                        
		}
                double monteCarlo = Math.exp((-r)*t)*(sum/nbSimulation);
                //Stop timing
                long end = System.currentTimeMillis();
                //Message
                running = false;
                MonteCarloThreads.mainFrame.jProgressBar1.setValue(101);
                JOptionPane.showMessageDialog(MonteCarloThreads.mainFrame, "Result : " + monteCarlo 
                                                                        + "\n   Time : " + (end - start)+" ms");
                //Progress bar back to 0
                progressBar1 = 0 ; progressBar2 = 0; 
                MonteCarloThreads.mainFrame.jProgressBar1.setValue(0);

        }

public double thread(  String CallPutFlag,
                        double s,
                        double x,
                        double r, 
                        double t,
                        double b,
                        double v,
			int nbSteps,
                        int nbSimulation,
                        double st,
                        double dt,
                        double drift,
                        double vSqrdt
                        ){
                Random random = new Random();
		for(int k=0 ; k<nbSteps ; k++){
                    st = st * Math.exp(drift + vSqrdt * random.nextGaussian());
                    
                }
                progressBar1++;
		return  st;
	}
}